package com.town.garden.component;

import cn.hutool.core.date.DatePattern;
import cn.hutool.core.date.DateTime;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.HexUtil;
import cn.hutool.core.util.IdUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONUtil;
import com.town.garden.chain.AbstractServerStartHandler;
import com.town.garden.constant.GlobalConstant;
import com.town.garden.entiy.AlarmEventToPulsarData;
import com.town.garden.entiy.AlertEvent;
import com.town.garden.entiy.ObjectInfo;
import com.town.garden.entiy.request.SearchPlaybackRtspUrlRequest;
import com.town.garden.entiy.request.SearchPlaybackRtspUrlRequestData;
import com.town.garden.entiy.response.SearchPlaybackRtspUrlResponse;
import com.town.garden.enums.StreamModEnum;
import com.town.garden.enums.TransportTypeEnum;
import com.town.garden.propertites.NvrProperties;
import com.town.garden.service.NvrPlaybackRtspUrlService;
import com.town.garden.template.S3Template;
import com.town.garden.utils.JavaCVRecordUtil;
import com.town.garden.utils.PulsarInitUtil;
import com.town.garden.utils.UrlParameterUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Component;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.Objects;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;

/**
 * @Description 从redis队列中取出事件进行处理组件
 * @E-mail cwm3412638@163.com
 * @Author cwm
 * @Date 2022/5/16
 */
@Slf4j
@Component(ProcessAlarmEventForRedisComponent.BEAN_NAME)
public class ProcessAlarmEventForRedisComponent extends AbstractServerStartHandler implements Runnable {
    public static final String BEAN_NAME = "processAlarmEventForRedisComponent";
    @Autowired
    private NvrProperties nvrProperties;
    @Autowired
    private ScheduledExecutorService scheduledExecutorService;
    @Autowired
    private NvrPlaybackRtspUrlService nvrPlaybackRtspUrlService;
    @Autowired
    private RedisRepository redisRepository;
    @Autowired
    private S3Template s3Template;
    @Autowired
    private PulsarInitUtil pulsarInitUtil;

    @Override
    public void handlerOperation() {
        for (int i = 0; i < nvrProperties.getProcessAlarmEventForRedisThreadNum(); i++) {
            scheduledExecutorService.scheduleAtFixedRate(this, 5, nvrProperties.getProcessAlarmEventForRedisTime(), TimeUnit.SECONDS);
        }
    }

    @Override
    public void run() {
        log.info("---------------------------------->执行处理视频线程");
        //从队列中取出告警事件对象
        Object o = redisRepository.rightPop(GlobalConstant.ALARM_EVENT_KEY);
        if (o instanceof AlertEvent) {
            AlertEvent alertEvent = (AlertEvent) o;
            log.info("alarm event time is :{}", alertEvent.getTime());
            //查询该事件的回放 url 地址
            SearchPlaybackRtspUrlRequest searchPlaybackRtspUrlRequest = encapsulationRequest(alertEvent);
            log.info("search PlaybackRtspUrl Parameter is :{}", JSONUtil.toJsonStr(searchPlaybackRtspUrlRequest));
            ResponseEntity<SearchPlaybackRtspUrlResponse> searchPlaybackRtspUrlResponseResponseEntity = nvrPlaybackRtspUrlService.searchPlaybackRtspUrl(searchPlaybackRtspUrlRequest);
            log.info("search PlaybackRtspUrl response is :{}", searchPlaybackRtspUrlResponseResponseEntity.getBody());
            if (StrUtil.isNotEmpty(Objects.requireNonNull(searchPlaybackRtspUrlResponseResponseEntity.getBody()).getData().getPlaybackUrl())) {
                String playbackRtspUrl = searchPlaybackRtspUrlResponseResponseEntity.getBody().getData().getPlaybackUrl();
                //生成视频文件名 告警事件-告警通道名称-告警通道Ip地址-告警类型
                String fileName = DateUtil.format(DateUtil.parse(alertEvent.getTime(), DatePattern.NORM_DATETIME_PATTERN), DatePattern.CHINESE_DATE_TIME_PATTERN)
                        + GlobalConstant.BAR + alertEvent.getChannelName()
                        + GlobalConstant.BAR + alertEvent.getChannelInfoData().getIpAddress()
                        + GlobalConstant.BAR + alertEvent.getAlertEnum() + GlobalConstant.VEDIO_PERFIX_NAME;
                //拼接视频输出零时地址
                String outputFile = nvrProperties.getTemporaryVideoStoragePath() + GlobalConstant.FIL_DIRECTORY_PREFIX + fileName;
                //生成视频封面图片名称 告警事件-告警通道名称-告警通道Ip地址-告警类型
                final String imageName = DateUtil.format(DateUtil.parse(alertEvent.getTime(), DatePattern.NORM_DATETIME_PATTERN), DatePattern.CHINESE_DATE_TIME_PATTERN)
                        + GlobalConstant.BAR + alertEvent.getChannelName() + GlobalConstant.BAR +
                        alertEvent.getChannelInfoData().getIpAddress() + GlobalConstant.BAR + alertEvent.getAlertEnum() +
                        GlobalConstant.IMAGE_PERFIX_NAME;
                //拼接图片输出零时地址
                final String imageOutPath = nvrProperties.getTemporaryImageStoragePath() + GlobalConstant.FIL_DIRECTORY_PREFIX + imageName;
                String startTime = UrlParameterUtils.getParamByUrl(playbackRtspUrl, "starttime");
                String endTime = UrlParameterUtils.getParamByUrl(playbackRtspUrl, "endtime");
                log.info("playbackRtspUrl starttime is :{},endtime is :{}", startTime, endTime);
                try {
                    //录制视频
                    JavaCVRecordUtil.frameRecord(playbackRtspUrl, outputFile, 1);
                    //判断文件是否存在 视频录制完毕
                    File file = new File(outputFile);
                    //上传文件到oss对象服务器
                    ObjectInfo videoObjectInfo = s3Template.upload(fileName, new FileInputStream(file));
                    //截取视频第一帧作为封面图片
                    JavaCVRecordUtil.getImage(outputFile, imageOutPath);
                    File imageFile = new File(imageOutPath);
                    //上传封面到oss服务器
                    ObjectInfo imageObjectInfo = s3Template.upload(nvrProperties.getImageBucketName(), imageName, new FileInputStream(imageFile));
                    if (Objects.nonNull(videoObjectInfo)
                            && StrUtil.isNotEmpty(videoObjectInfo.getObjectUrl())
                            && Objects.nonNull(imageObjectInfo)
                            && StrUtil.isNotEmpty(imageObjectInfo.getObjectUrl())) {
                        log.info("upload video success ,url is :{},path is :{}", videoObjectInfo.getObjectUrl(), videoObjectInfo.getObjectPath());
                        //根据事件mac地址加通道查询摄像头信息 推送给pulsar
                        if (Objects.nonNull(alertEvent.getAlertEnum())) {
                            AlarmEventToPulsarData alarmEventToPulsarData = new AlarmEventToPulsarData();
                            alarmEventToPulsarData.setChannelName(alertEvent.getChannelName());
                            alarmEventToPulsarData.setChannelIp(alertEvent.getChannelInfoData().getIpAddress());
                            alarmEventToPulsarData.setNvrMac(nvrProperties.getMac());
                            alarmEventToPulsarData.setUrl(videoObjectInfo.getObjectUrl());
                            alarmEventToPulsarData.setTime(alertEvent.getTime());
                            alarmEventToPulsarData.setCoverPicture(imageObjectInfo.getObjectUrl());
                            alarmEventToPulsarData.setType(alertEvent.getAlertEnum().getCode());
                            log.info("send alarm event to pulsar");
                            pushAlarmEventToPulsar(alarmEventToPulsarData);
                        }
                    }
                } catch (Exception e) {
                    e.printStackTrace();
                } finally {
                    if (Files.exists(Path.of(outputFile))) {
                        try {
                            Files.delete(Path.of(outputFile));
                        } catch (IOException e) {
                            e.printStackTrace();
                        }
                    }

                    if (Files.exists(Path.of(imageOutPath))) {
                        try {
                            Files.delete(Path.of(imageOutPath));
                        } catch (IOException e) {
                            e.printStackTrace();
                        }
                    }
                }
            }
        }
    }

    /**
     * 封装请求对象
     *
     * @param alertEvent
     * @return
     */
    private SearchPlaybackRtspUrlRequest encapsulationRequest(AlertEvent alertEvent) {
        SearchPlaybackRtspUrlRequest searchPlaybackRtspUrlRequest = new SearchPlaybackRtspUrlRequest();
        SearchPlaybackRtspUrlRequestData searchPlaybackRtspUrlRequestData = new SearchPlaybackRtspUrlRequestData();
        searchPlaybackRtspUrlRequestData.setChannel(alertEvent.getChannelName());
        searchPlaybackRtspUrlRequestData.setTransport_type(TransportTypeEnum.TCP.getName());
        searchPlaybackRtspUrlRequestData.setStream_mod(StreamModEnum.MAINSTREAM.getName());
        String time = alertEvent.getTime();
        //计算播放时间(UTC时间  = 当前时间 -8小时)
        DateTime parse = DateUtil.parse(time, DatePattern.NORM_DATETIME_PATTERN);
        long utc = parse.getTime() - (1000 * 60 * 60 * 8);
        DateTime utcDate = DateUtil.date(utc);
        String year = DateUtil.format(utcDate, DatePattern.NORM_DATE_PATTERN);
        //设置开始年月分
        searchPlaybackRtspUrlRequestData.setStart_date(year);
        searchPlaybackRtspUrlRequestData.setEnd_date(year);
        //设置开始 结束时间
        String startDay = DateUtil.format(utcDate, DatePattern.NORM_TIME_PATTERN);
        String endDay = DateUtil.format(DateUtil.date(utc + nvrProperties.getPlaybackRtspUrlTime()), DatePattern.NORM_TIME_PATTERN);
        searchPlaybackRtspUrlRequestData.setStart_time(startDay);
        searchPlaybackRtspUrlRequestData.setEnd_time(endDay);
        //告警视频7FFFFFFE 全部视频 FFFFFFFF
        searchPlaybackRtspUrlRequestData.setRecord_type(HexUtil.hexToLong("7FFFFFFE"));
        searchPlaybackRtspUrlRequest.setData(searchPlaybackRtspUrlRequestData);
        return searchPlaybackRtspUrlRequest;
    }

    /**
     * 推送告警给puslar
     *
     * @param alarmEventToPulsarData
     */
    private void pushAlarmEventToPulsar(AlarmEventToPulsarData alarmEventToPulsarData) {
        pulsarInitUtil.sendMsg(IdUtil.fastSimpleUUID(), JSONUtil.toJsonStr(alarmEventToPulsarData), pulsarInitUtil.getProducer(GlobalConstant.ALARM_EVENT_VIDEO));
    }
}
